package n13_reentrantlock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import static utils.Sleeper.sleep;

/**
 * @author fu
 * @date 2022-01-10 21:21
 * 概要：
 * ---------------------------------------------------------------
 * |                                                              |
 * |  synchronized 的条件变量 ：某个线程获得锁后 当条件不满足 进入 waitSet休息室等待，不满足条件线程都在一个 休息室 等待
 * |  ReentrantLock 条件变量  ： 支持多个 条件变量； 多个休息室        |
 * |                                                             |
 * |=============================================================
 *
 * 使用流程：
 *
 *     await 之前需要获得锁；就如synchronized进入waitSet之前先必须得是Owner锁的主人
 *
 *     await 执行后，释放锁，进入 conditionObject等待；
 *
 *     await 线程被唤醒后（打断、或超时）去重新竞争lock锁
 *
 *     竞争lock锁成功后，从 await后继续执行
 *
 */
@Slf4j(topic = "c.T6")
public class T6 {

    static boolean hasYan = false;
    static boolean hasWaimai = false;

    static ReentrantLock lock = new ReentrantLock();
    // 等烟休息室  等外卖休息室
    static Condition waitYan = lock.newCondition();
    static Condition waitWaimai = lock.newCondition();

    public static void main(String[] args) {

        new Thread(() -> {

            lock.lock();

            try {
                log.debug("有烟没？[{}]", hasYan);

                while (!hasYan) {
                    log.debug("没烟，先歇会！");

                    waitYan.await();// 阻塞等待
                }

                log.debug("可以开始干活了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }, "---小南---").start();

        new Thread(() -> {

            lock.lock();

            try {
                log.debug("外卖送到没？[{}]", hasWaimai);

                while (!hasWaimai) {
                    log.debug("没外卖，先歇会！");

                    waitWaimai.await();// 阻塞等待
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

            log.debug("可以开始干活了");
        }, "+++小女+++").start();

        //-----------------------------------------------------------------------------------------
        sleep(3);
        // 送外卖
        new Thread(() -> {

            lock.lock();

            try {
                hasWaimai = true;
                log.debug("外卖---到了噢！");
                waitWaimai.signal();
            } finally {
                lock.unlock();
            }

        }, "-送外卖的-").start();

        sleep(3);
        // 送 烟
        new Thread(() -> {

            lock.lock();
            try {
                hasYan = true;
                log.debug("香烟---到了噢！");
                waitYan.signal();
            } finally {
                lock.unlock();
            }

        }, "-送香烟的-").start();
    }

}
